上一个版本的问题
接这篇文章,聊聊参数检查工具 param-check 的完善。
按照之前的接口设计,链式调用表示“与”,参数表表示“或”,自然产生了一个问题——如果我要表达“(A与B)或(C与D)”这样的逻辑组合应该怎么办?
以及,由于 not 调用只对它后面的第一个调用生效,那么如果我要实现“非(A与B)”,该怎么办?
总结起来,实际上就是给逻辑表达式加括号的问题。
or 和 and 方法
为了自由表达与或关系,我们需要扩展一下规则。分析可知,函数调用的参数表是一个天然的括号,所以只用来表达“或”太奢侈了。我们添加方法 or 和 and,使之能表达与和或。但是这里有个问题,param-check 目前的接口都是即时计算的,如果你把调用串当做参数传递,没有传进去之前已经计算完了,异常捕获不到,没法实现逻辑关系。比如:
check(a).or(check(a).gt(1).lt(3), check(a).gt(2).lt(4));
上面的代码是没法实现 or 的。
解决方法比较容易想到的有两个:
改变接口模式,不再抛出异常,二是返回 false。这样 or 和 and 就很容易实现了,但是链式调用就没法实现了。
-
提取 check 的调用路径,使得一个检查过程能保存在一个对象(高阶函数)里,当做参数传到其它函数中,本质上这是一种函数式编程方法。如果不考虑到书写方便,这是很容易实现的:
function myCheck(a) { check(a).gt(1).lt(3); } function myCheck2(a) { check(a).is('string'); } +function (a) { check(a).or(myCheck, myCheck2); }(2);
“使用链式调用记录链式调用路径”
显然上面的写法非常不方便,所以我实现了一种更好用的接口,使用同样的链式调用方式,实现调用路径提取和参数缓存。具体的实现方式在这篇文章里。最终实现了这样的效果:
// 检查 param 是否在区间(1,3) 与 (2,4) 的交集内
check(param, 'param').and(check.policy.gt(1).lt(3), check.policy.gt(2).lt(4));
// 检查 param 是否在区间(1,2) 与 (3,4) 的并集内
check(param, 'param').or(check.policy.gt(1).lt(2), check.policy.gt(3).lt(4));
function myCheck(obj) {
return obj.length > 4;
}
// 检查 param 是否是数组并且长度大于 4
check(param, 'param').and(check.policy.is('array'), myCheck);
// 检查 param 是否*不是*[1,3]之间的偶数(即2)
check(param, 'param').not.and(
check.policy.is('number').not.lt(1).not.gt(3),
function (obj) {
return obj % 2 === 0;
});
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。